/*
** Copyright (C) 2010 Calin Radoni
**
** This file is part of CHScanner.
**
** CHScanner is free software: you can redistribute it and/or modify
** it under the terms of the GNU General Public License as published by
** the Free Software Foundation, either version 3 of the License, or
** (at your option) any later version.
**
** CHScanner is distributed in the hope that it will be useful,
** but WITHOUT ANY WARRANTY; without even the implied warranty of
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
** GNU General Public License for more details.
**
** You should have received a copy of the GNU General Public License
** along with CHScanner. If not, see <http://www.gnu.org/licenses/>.
*/

#include "StdAfx.h"
#include "ScanMethodPassive.h"

//--------------------------------------------------------------------

ScanMethodPassive::ScanMethodPassive(void)
{
	myType = __wmtPassive;

//	ethernetCounters.Initialize();

	rBuffer1[0]  = 0x07;	// len = 7
	rBuffer1[1]  = 0x69;	// 'i'
	rBuffer1[2]  = 0x6E;	// 'n'
	rBuffer1[3]  = 0x2D;	// '-'
	rBuffer1[4]  = 0x61;	// 'a'
	rBuffer1[5]  = 0x64;	// 'd'
	rBuffer1[6]  = 0x64;	// 'd'
	rBuffer1[7]  = 0x72;	// 'r'
	rBuffer1[8]  = 0x04;	// len = 4
	rBuffer1[9]  = 0x61;	// 'a'
	rBuffer1[10] = 0x72;	// 'r'
	rBuffer1[11] = 0x70;	// 'p'
	rBuffer1[12] = 0x61;	// 'a'
	rBuffer1[13] = 0x00;	// len = 0 (address done)
	rBuffer1[14] = 0x00;	//
	rBuffer1[15] = 0x0C;	// TYPE: PTR
	rBuffer1[16] = 0x00;	//
	rBuffer1[17] = 0x01;	// CLASS: IN

	rBuffer2[0] = 0xC0;	//
	rBuffer2[1] = 0x0C;	// Name
	rBuffer2[2] = 0x00;	//
	rBuffer2[3] = 0x0C;	// TYPE: PTR
	rBuffer2[4] = 0x00;	//
	rBuffer2[5] = 0x01;	// CLASS: IN
}

ScanMethodPassive::~ScanMethodPassive(void)
{
}

//--------------------------------------------------------------------

int ScanMethodPassive::InternalInit(void)
{
	machInfoList->globalInfo.ethernetCounters.Initialize();

	return MSR_ERR_OK;
}

//--------------------------------------------------------------------

int ScanMethodPassive::InternalExecute(void)
{
	DWORD ts, te, td, tsx;

	dataProcessed = false;
	ts = GetTickCount();
	tsx = ts;

	while(!stopStopStop){
		CheckResponses();

		te = GetTickCount();

		td = ComputeDeltaTime(ts, te);
		if(td>3000){
			if(dataProcessed){
				if(hWnd!=NULL)
					SendMessage(hWnd, CHS_MSG_UPDATE_DATA, 1, 0);
				dataProcessed = false;
				tsx = te;
			}
			ts = te;
		}

		td = ComputeDeltaTime(tsx, te);
		if(td>60000){
			if(hWnd!=NULL)
				SendMessage(hWnd, CHS_MSG_UPDATE_DATA, 1, 0);
			tsx = te;
		}
	}

	if(hWnd!=NULL)
		SendMessage(hWnd, CHS_MSG_UPDATE_DATA, 1, 0);

	return MSR_ERR_OK;
}

//--------------------------------------------------------------------

void ScanMethodPassive::AddMachine(BYTE* srcIpIn, BYTE* srcMacIn)
{
	AddMachineAndPort(srcIpIn, srcMacIn, 0, __wmtPassive);
}

void ScanMethodPassive::AddMachineAndPort(BYTE* srcIpIn, BYTE* srcMacIn, WORD portIn, WorkMethodType methodIn)
{
	if(srcIpIn==NULL) return;
	if(srcMacIn==NULL) return;

	addrX.Initialize();
	addrX.addrIP.Set(srcIpIn[0], srcIpIn[1], srcIpIn[2], srcIpIn[3]);
	addrX.addrMAC.LoadFromBytePtr(srcMacIn);
	addrX.alive = true;
	addrX.respReceived = true;

	machX.Initialize();
	machX.address.LoadFromPointer(&addrX);

	if(portIn>0){
		portX.Initialize();
		portX.method = methodIn;
		portX.port = portIn;
		machX.AddPortInfoNoDuplicates(&portX);
	}

	machInfoList->Add(&machX);
}

void ScanMethodPassive::AddMachineAndDnsName(char* nameIn, DWORD ipIn, DWORD ttlIn, WORD typeIn)
{
	MDnsName dnsName;

	if(nameIn==NULL) return;

	addrX.Initialize();
	addrX.addrIP.Set(ipIn);
	addrX.addrMAC.Initialize();

	machX.Initialize();
	machX.address.LoadFromPointer(&addrX);

	dnsName.nameDns = nameIn;
	dnsName.nameDnsTTL = ttlIn;
	dnsName.nameType = typeIn;
	machX.AddDnsNameNoDuplicates(&dnsName);

	machInfoList->Add(&machX);
}

void ScanMethodPassive::AddMachineSSDP(BYTE* srcIpIn, BYTE* srcMacIn)
{
	if(srcIpIn==NULL) return;
	if(srcMacIn==NULL) return;

	addrX.Initialize();
	addrX.addrIP.Set(srcIpIn[0], srcIpIn[1], srcIpIn[2], srcIpIn[3]);
	addrX.addrMAC.LoadFromBytePtr(srcMacIn);
	addrX.alive = true;
	addrX.respReceived = true;

	machX.Initialize();
	machX.address.LoadFromPointer(&addrX);
	machX.ssdp = true;

	machInfoList->Add(&machX);
}

//--------------------------------------------------------------------

void ScanMethodPassive::AddMachine6(BYTE* srcIpIn, BYTE* srcMacIn)
{
	AddMachine6AndPort(srcIpIn, srcMacIn, 0, __wmtPassive);
}

void ScanMethodPassive::AddMachine6AndPort(BYTE* srcIpIn, BYTE* srcMacIn, WORD portIn, WorkMethodType methodIn)
{
	if(srcIpIn==NULL) return;
	if(srcMacIn==NULL) return;

	in6_addr ia6;

	memcpy(ia6.u.Byte, srcIpIn, 16);
	addrX.Initialize();
	addrX.addrIPv6.Set(&ia6);
	addrX.addrMAC.LoadFromBytePtr(srcMacIn);
	addrX.alive = true;
	addrX.respReceived = true;

	if(addrX.addrMAC.IsEmpty()){
		OutputDebugString(_T("Empty MAC\n"));
		// TODO remove (???) this
	}

	machX.Initialize();
	machX.address.LoadFromPointer(&addrX);

	if(portIn>0){
		portX.Initialize();
		portX.method = methodIn;
		portX.port = portIn;
		machX.AddPortInfoNoDuplicates(&portX);
	}

	machInfoList->Add(&machX);
}

//--------------------------------------------------------------------

void ScanMethodPassive::AddMachineIPX(BYTE *srcNetIn, BYTE *srcHostIn)
{
	MMachineInfo *mach;
	if(srcNetIn==NULL) return;
	if(srcHostIn==NULL) return;

	addrX.Initialize();
	addrX.alive = true;
	addrX.respReceived = true;

	addrX.addrMAC.LoadFromBytePtr(srcHostIn);

	if(addrX.addrMAC.IsEmpty()) return;
	
	mach = machInfoList->GetMachineInfoByMacAddr(&addrX.addrMAC);
	if(mach!=NULL){
		mach->address.addrIPX.SetNet(srcNetIn);
		mach->address.addrIPX.SetHost(srcHostIn);
		return;
	}

	addrX.addrIPX.SetNet(srcNetIn);
	addrX.addrIPX.SetHost(srcHostIn);

	machX.Initialize();
	machX.address.LoadFromPointer(&addrX);

	machInfoList->Add(&machX);
}

//--------------------------------------------------------------------

void ScanMethodPassive::ProcessArpAny(BYTE* dataIn, int sizeIn)
{
	machInfoList->globalInfo.ethernetCounters.cntARP++;
	dataProcessed = true;

	if(sizeIn<42) return; // incomplete ARP packet

	FullARPPacket *arpp;

	arpp = (FullARPPacket*)dataIn;

	switch(ntohs(arpp->arpCode)){
		case 1 : // request
			AddMachine(arpp->senderPA, arpp->senderHA);
			break;

		case 2 : // reply
			AddMachine(arpp->senderPA, arpp->senderHA);
			break;
	}
}

//--------------------------------------------------------------------

void ScanMethodPassive::ProcessIcmpAny(BYTE* dataIn, int sizeIn, BYTE* srcMAC)
{
	machInfoList->globalInfo.ethernetCounters.cntICMPv4++;
	dataProcessed = true;

	if(sizeIn<20) return; // incomplete IP packet

	IPHeaderPG *iph;

	iph = (IPHeaderPG*)dataIn;
	AddMachine(iph->Source, srcMAC);
}

//---------------------------------------------------------------------------

void ScanMethodPassive::ProcessIgmp(BYTE* dataIn, int sizeIn, BYTE* srcMAC)
{
	machInfoList->globalInfo.ethernetCounters.cntIPv4Other++;
	dataProcessed = true;

	if(sizeIn<32) return; // sizeof(IPHeaderPG) + options(=4bytes) + 8_bytes_for_min_IGMP

	IPHeaderPG        *iph;
	IGMPHeaderPG      *igmph;
	IGMPReportPG      *igmpr;
	IGMPGroupRecordPG *igmpg;
	int               dataOffset;
	in_addr           ga;
	int               cnt, gCnt, pos;

	iph = (IPHeaderPG*)dataIn;
	dataOffset  = (int)(iph->HLV & 0x0F);
	dataOffset *= 4;
	if(sizeIn<(dataOffset + 8)) return;	// incomplete IP+IGMP packet

	igmph = (IGMPHeaderPG*)&dataIn[dataOffset];
	switch(igmph->Type){
		case 0x11 : // Membership Query
		case 0x12 : // Version 1 Membership Report
		case 0x16 : // Version 2 Membership Report
		case 0x17 : // Version 2 Leave Group
			ga.S_un.S_un_b.s_b1 = igmph->GroupAddress[0];
			ga.S_un.S_un_b.s_b2 = igmph->GroupAddress[1];
			ga.S_un.S_un_b.s_b3 = igmph->GroupAddress[2];
			ga.S_un.S_un_b.s_b4 = igmph->GroupAddress[3];
			AddMachineIGMP(iph->Source, srcMAC, igmph->Type, ga.S_un.S_addr, 0);
			break;

		case 0x22 : // Version 3 Membership Report
			igmpr = (IGMPReportPG*)&dataIn[dataOffset];
			cnt   = ntohs(igmpr->NoOfGroupRecords);
			pos   = dataOffset + 8; // where 8 is the size of IGMPReportPG
			while(cnt>0){
				pos += 8;	// where 8 is the size of IGMPGroupRecordPG
				if(sizeIn<pos) return;

				igmpg = (IGMPGroupRecordPG*)&dataIn[pos];
				gCnt  = ntohs(igmpg->NumberOfSources);
				pos += 4*gCnt;
				if(sizeIn<pos) return;

				ga.S_un.S_un_b.s_b1 = igmpg->MulticastAddress[0];
				ga.S_un.S_un_b.s_b2 = igmpg->MulticastAddress[1];
				ga.S_un.S_un_b.s_b3 = igmpg->MulticastAddress[2];
				ga.S_un.S_un_b.s_b4 = igmpg->MulticastAddress[3];

				AddMachineIGMP(iph->Source, srcMAC, igmph->Type, ga.S_un.S_addr, igmpg->RecordType);
	
				cnt--;
			}
			break;

		default :
			ga.S_un.S_un_b.s_b1 = igmph->GroupAddress[0];
			ga.S_un.S_un_b.s_b2 = igmph->GroupAddress[1];
			ga.S_un.S_un_b.s_b3 = igmph->GroupAddress[2];
			ga.S_un.S_un_b.s_b4 = igmph->GroupAddress[3];
			AddMachineIGMP(iph->Source, srcMAC, igmph->Type, ga.S_un.S_addr, 0);
			return;
	}
}

void ScanMethodPassive::AddMachineIGMP(BYTE* srcIpIn, BYTE* srcMacIn, BYTE typeIn, DWORD grpAddrIpIn, BYTE recordTypeIn)
{
	if(srcIpIn==NULL) return;
	if(srcMacIn==NULL) return;

	addrX.Initialize();
	addrX.addrIP.Set(srcIpIn[0], srcIpIn[1], srcIpIn[2], srcIpIn[3]);
	addrX.addrMAC.LoadFromBytePtr(srcMacIn);
	addrX.alive = true;
	addrX.respReceived = true;

	machX.Initialize();
	machX.address.LoadFromPointer(&addrX);

	if(typeIn!=0){
		igmpX.Initialize();
		igmpX.type = typeIn;
		igmpX.addr.Set(grpAddrIpIn);
		igmpX.recordType = recordTypeIn;
		machX.AddIgmpPackNoDuplicates(&igmpX);
	}

	machInfoList->Add(&machX);
}

//---------------------------------------------------------------------------

void ScanMethodPassive::ProcessTcp(BYTE* dataIn, int sizeIn, BYTE* srcMAC)
{
	machInfoList->globalInfo.ethernetCounters.cntTCPv4++;
	dataProcessed = true;

	if(sizeIn<20) return; // incomplete IP packet

	IPHeaderPG  *iph;
	TCPHeaderPG *tcph;
	int         dataOffset;

	iph = (IPHeaderPG*)dataIn;
	dataOffset  = (int)(iph->HLV & 0x0F);
	dataOffset *= 4;
	if(sizeIn<(dataOffset + 20)) return;	// incomplete IP+TCP packet

	tcph = (TCPHeaderPG*)&dataIn[dataOffset];

	if(tcph->Flags==(TH_SYN | TH_ACK)){
		AddMachineAndPort(iph->Source, srcMAC, ntohs(tcph->SourcePort), __wmtPassiveTCP);
	}
	else{
		AddMachine(iph->Source, srcMAC);
	}
}

//---------------------------------------------------------------------------

bool ScanMethodPassive::ExtractAddressFromResponse(BYTE* dataIn, int sizeIn, DWORD* addrOut, int* lenOut)
{
	if(dataIn==NULL) return false;
	if(sizeIn<1) return false;
	if(addrOut==NULL) return false;
	if(lenOut==NULL) return false;

	BYTE tokenLen;
	BYTE chBuff[4];
	int idx;
	in_addr ia;

	*addrOut = 0;
	*lenOut  = 0;

	idx = 0;

	memset(chBuff, 0, 4);
	tokenLen = (unsigned int)dataIn[idx];
	if(tokenLen>3) return false;
	memcpy(chBuff, &dataIn[idx+1], tokenLen);
	ia.S_un.S_un_b.s_b4 = atoi((char*)chBuff);
	idx += tokenLen + 1;

	memset(chBuff, 0, 4);
	tokenLen = (unsigned int)dataIn[idx];
	if(tokenLen>3) return false;
	memcpy(chBuff, &dataIn[idx+1], tokenLen);
	ia.S_un.S_un_b.s_b3 = atoi((char*)chBuff);
	idx += tokenLen + 1;

	memset(chBuff, 0, 4);
	tokenLen = (unsigned int)dataIn[idx];
	if(tokenLen>3) return false;
	memcpy(chBuff, &dataIn[idx+1], tokenLen);
	ia.S_un.S_un_b.s_b2 = atoi((char*)chBuff);
	idx += tokenLen + 1;

	memset(chBuff, 0, 4);
	tokenLen = (unsigned int)dataIn[idx];
	if(tokenLen>3) return false;
	memcpy(chBuff, &dataIn[idx+1], tokenLen);
	ia.S_un.S_un_b.s_b1 = atoi((char*)chBuff);
	idx += tokenLen + 1;

	// dataIn[idx...] should be '07'in-addr'04'arpa'00000C0001
	// 07 69 6e 2d 61 64 64 72 04 61 72 70 61 00, 00 0C, 00 01

	if(memcmp(rBuffer1, &dataIn[idx], 18)!=0)
		return false;

	*addrOut = ia.S_un.S_addr;
	*lenOut  = idx + 18;

	return true;
}

bool ScanMethodPassive::ExtractNameFromResponse(BYTE* dataIn, int sizeIn, int* lenOut)
{
	if(dataIn==NULL) return false;
	if(sizeIn<1) return false;
	if(lenOut==NULL) return false;

	bool done;

	*lenOut  = 0;
	int idx;

	idx = 0;
	done = false;
	memset(rBuffer3, 0, 256);
	while(!done){
		rBuffer3[idx] = dataIn[idx];
		if(dataIn[idx]==0) done = true;
		else if(idx>255) done = true;
		     else idx++;
	}
	
	idx += 4;
	if(idx>=sizeIn || idx>255)
		return false;

	*lenOut = idx;

	return true;
}

void ScanMethodPassive::FormatName(BYTE* dataIn, int sizeIn)
{
	int i;
	bool done;

	done = false;
	for(i=0; i<sizeIn && !done; i++){
		if(dataIn[i]==0) done = true;
		else{
			if(dataIn[i]<32)
				dataIn[i] = '.';
		}
	}
}

void ScanMethodPassive::ProcessDnsResponse(BYTE* srcIP, BYTE* srcMAC, BYTE* packIn, int sizeIn)
{
	DNSRequestHeader *dnrh;
	WORD             flags;
	int              idx;
	DWORD            queryAddress;
	int              querySize;
	int              len;
	WORD             *wLen;
	int              i;

	dnrh = (DNSRequestHeader*)packIn;
	flags = ntohs(dnrh->flags);
	if(!(flags & 0x8000)){
		// not a DNS response packet, skipping
		return;
	}
	flags &= 0x000F;
	if(flags!=0){
		// the DNS response indicates an error, skipping
		return;
	}

	if(dnrh->answerRR==0){
		// no response ?
		return;
	}

	// next, at packIn[12]
	//   - the query
	//   - the answer
	idx = 12;
	if(idx>sizeIn){
		// incomplete, skip
		return;
	}

	bool found;
	found = false;
	if(!ExtractAddressFromResponse(&packIn[idx], sizeIn-idx, &queryAddress, &querySize)){
		// it may be an A type
		for(i=idx; i<sizeIn && !found; i++)
			if(packIn[i]==0)
				found = true;
		if(!found) return;

		if(packIn[i]==0x00 && packIn[i+1]==0x01){
			// yes, this is an A record
			if(!ExtractNameFromResponse(&packIn[idx], sizeIn-idx, &querySize))
				return;
		}
		else return;
	}

	idx += querySize;
	if(idx>sizeIn){
		// incomplete, skip
		return;
	}

	in_addr ia;

	if(found){
		idx++;
		if(packIn[idx++]!=0xc0) return;
		if(packIn[idx++]!=0x0c) return;
		if(packIn[idx++]!=0x00) return;
		if(packIn[idx++]!=0x01) return;
		if(packIn[idx++]!=0x00) return;
		if(packIn[idx++]!=0x01) return;

		idx += 4;

		if(packIn[idx++]!=0x00) return;
		if(packIn[idx++]!=0x04) return;

		ia.S_un.S_un_b.s_b1 = packIn[idx++];
		ia.S_un.S_un_b.s_b2 = packIn[idx++];
		ia.S_un.S_un_b.s_b3 = packIn[idx++];
		ia.S_un.S_un_b.s_b4 = packIn[idx];

		FormatName(&rBuffer3[1], querySize-4);

		AddMachineAndDnsName((char*)&rBuffer3[1], ia.S_un.S_addr, 0 /* DNS TTL */, 1 /* A */);
		return;
	}

	if(memcmp(&packIn[idx], rBuffer2, 6)!=0)
		return;

	ia.S_un.S_un_b.s_b1 = packIn[idx+9];
	ia.S_un.S_un_b.s_b2 = packIn[idx+8];
	ia.S_un.S_un_b.s_b3 = packIn[idx+7];
	ia.S_un.S_un_b.s_b4 = packIn[idx+6];

	idx += 10;					// skip 4 bytes for DNS record's TTL
	if(idx>sizeIn){
		// incomplete, skip
		return;
	}

	wLen = (WORD*)&packIn[idx];
	len = ntohs(*wLen);

	memset(rBuffer3, 0, 256);
	if(len>255){
		// nasol, nume mai mare decat am prevazut
		len = 255;
	}
	memcpy(rBuffer3, &packIn[idx+2], len);
	idx += len + 2;
	if(idx>sizeIn){
		// incomplete, skip
		return;
	}

	FormatName(&rBuffer3[1], len-1);

	AddMachineAndDnsName((char*)&rBuffer3[1], queryAddress, 0 /* DNS TTL */, 1 /* A */);
}

//---------------------------------------------------------------------------

void ScanMethodPassive::ProcessNTPResponse(BYTE* srcIP, BYTE* srcMAC, BYTE* packIn, int sizeIn)
{
	NTPMessage *ntph;
	BYTE bbb;

	if(sizeIn<48){
		// packet too small
		return;
	}

	ntph = (NTPMessage*)packIn;
	bbb = NTPMessageVersionNumber(ntph->LVM);
	if(bbb<2) return;	// version too small
	if(bbb>4) return;	// version too high
	bbb = NTPMessageMode(ntph->LVM);
	if(bbb!=4) return;	// not server

	machInfoList->globalInfo.ntpIP.Set(srcIP[0], srcIP[1], srcIP[2], srcIP[3]);
	machInfoList->globalInfo.ntpMAC.LoadFromBytePtr(srcMAC);
	memcpy(&(machInfoList->globalInfo.ntpMessage), packIn, 48);
}

//---------------------------------------------------------------------------

void ScanMethodPassive::ProcessSSDP(BYTE* srcIP, BYTE* srcMAC, BYTE* packIn, int sizeIn)
{
	dataProcessed = true;

	AddMachineSSDP(srcIP, srcMAC);
}

//---------------------------------------------------------------------------

void ScanMethodPassive::ProcessUdpEx(BYTE* dataIn, int sizeIn, BYTE* srcMAC)
{
	machInfoList->globalInfo.ethernetCounters.cntUDPv4++;
	dataProcessed = true;

	if(sizeIn<20) return; // incomplete IP packet

	IPHeaderPG *iph;

	iph = (IPHeaderPG*)dataIn;
	AddMachine(iph->Source, srcMAC);

	UDPHeaderPG *udph;
	int         dataOffset;
	int         packSize;

	dataOffset  = (int)(iph->HLV & 0x0F);
	dataOffset *= 4;
	if(sizeIn<(dataOffset+8)){
		// incomplete packet
		return;
	}

	udph = (UDPHeaderPG*)&dataIn[dataOffset];
	if(sizeIn<(ntohs(udph->Length) + dataOffset)){
		// incomplete packet
		return;
	}

	packSize = dataOffset + 8;

	switch(ntohs(udph->SourcePort)){
		case 53 :
			// DNS
			ProcessDnsResponse(iph->Source, srcMAC, &dataIn[packSize], sizeIn - packSize);
			break;

		case 123 :
			// Network Time Protocol
			ProcessNTPResponse(iph->Source, srcMAC, &dataIn[packSize], sizeIn - packSize);
			break;

		default:
			break;
	}

	switch(ntohs(udph->DestinationPort)){
		case 1900 :
			// SSDP
			ProcessSSDP(iph->Source, srcMAC, &dataIn[packSize], sizeIn - packSize);
			break;

		default:
			break;
	}
}

//---------------------------------------------------------------------------

void ScanMethodPassive::ProcessOtherIpPacket(BYTE* dataIn, int sizeIn, BYTE* srcMAC)
{
	machInfoList->globalInfo.ethernetCounters.cntIPv4Other++;
	dataProcessed = true;

	if(sizeIn<20) return; // incomplete IP packet

	IPHeaderPG *iph;

	iph = (IPHeaderPG*)dataIn;
	AddMachine(iph->Source, srcMAC);
}

//---------------------------------------------------------------------------

void ScanMethodPassive::ProcessEchoReply6(BYTE* dataIn, int sizeIn, BYTE* srcIP, BYTE* srcMAC)
{
}

void ScanMethodPassive::ProcessMulticastListenerReport(BYTE* dataIn, int sizeIn, BYTE* srcIP, BYTE* srcMAC)
{
}

void ScanMethodPassive::ProcessRouterAdvertisement(BYTE* dataIn, int sizeIn, BYTE* srcIP, BYTE* srcMAC)
{
}

void ScanMethodPassive::ProcessNeighborAdvertisement(BYTE* dataIn, int sizeIn, BYTE* srcIP, BYTE* srcMAC)
{
}

void ScanMethodPassive::ProcessIcmp6Any(BYTE* dataIn, int sizeIn, BYTE* srcIP, BYTE* srcMAC)
{
	machInfoList->globalInfo.ethernetCounters.cntICMPv6++;
	dataProcessed = true;

	AddMachine6(srcIP, srcMAC);
}

//---------------------------------------------------------------------------

void ScanMethodPassive::ProcessTcp6(BYTE* dataIn, int sizeIn, BYTE* srcIP, BYTE* srcMAC)
{
	machInfoList->globalInfo.ethernetCounters.cntTCPv6++;
	dataProcessed = true;

	if(sizeIn<sizeof(TCPHeaderPG)) return;

	TCPHeaderPG *tcph;

	tcph = (TCPHeaderPG*)dataIn;

	if(tcph->Flags==(TH_SYN | TH_ACK)){
		AddMachine6AndPort(srcIP, srcMAC, ntohs(tcph->SourcePort), __wmtPassiveTCP);
	}
	else{
		AddMachine6(srcIP, srcMAC);
	}
}

//---------------------------------------------------------------------------

void ScanMethodPassive::ProcessUdp6(BYTE* dataIn, int sizeIn, BYTE* srcIP, BYTE* srcMAC)
{
	machInfoList->globalInfo.ethernetCounters.cntUDPv6++;
	dataProcessed = true;

//	if(sizeIn<sizeof(UDPHeaderPG)) return;

//	UDPHeaderPG *udph;

//	udph = (UDPHeaderPG*)dataIn;

	AddMachine6(srcIP, srcMAC);
}

//---------------------------------------------------------------------------

void ScanMethodPassive::ProcessOther6Packet(BYTE* dataIn, int sizeIn, BYTE* srcIP, BYTE* srcMAC)
{
	machInfoList->globalInfo.ethernetCounters.cntIPv6Other++;
	dataProcessed = true;
}

//---------------------------------------------------------------------------

void ScanMethodPassive::ProcessIPXorSPX(BYTE* dataIn, int sizeIn, BYTE* srcMAC)
{
	machInfoList->globalInfo.ethernetCounters.cntEthOther++;
	dataProcessed = true;

	IPXHeader *ipxH;

	if(sizeIn<30) return;
	ipxH = (IPXHeader*)dataIn;

	AddMachineIPX(ipxH->SrcNetwork, ipxH->SrcNode);
}

//---------------------------------------------------------------------------

void ScanMethodPassive::ProcessSTP(BYTE* dataIn, int sizeIn, BYTE* srcMAC)
{
	machInfoList->globalInfo.ethernetCounters.cntEthOther++;
	dataProcessed = true;

	STPPacket1PG *stp1h;
	STPPacket2PG *stp2h;

	if(sizeIn<35) return;

	stp1h = (STPPacket1PG*)&dataIn[0];
	stp2h = (STPPacket2PG*)&dataIn[5];

	mstpX.Initialize();
	mstpX.ProtocolId       = ntohs(stp1h->ProtocolId);
	mstpX.Version          = stp1h->Version;
	mstpX.MessageType      = stp1h->MessageType;
	mstpX.Flags            = stp1h->Flags;
	mstpX.RootIdPriority   = ntohs(stp2h->RootIdPriority);
	mstpX.RootPathCost     = ntohl(stp2h->RootPathCost);
	mstpX.BridgeIdPriority = ntohs(stp2h->BridgeIdPriority);
	mstpX.PortId           = ntohs(stp2h->PortId);
	mstpX.MessageAge       = ntohs(stp2h->MessageAge);
	mstpX.MaximumAge       = ntohs(stp2h->MaximumAge);
	mstpX.HelloTime        = ntohs(stp2h->HelloTime);
	mstpX.ForwardDelay     = ntohs(stp2h->ForwardDelay);

	for(int i=0; i<6; i++){
		mstpX.RootIdMAC[i]   = stp2h->RootIdMAC[i];
		mstpX.BridgeIdMAC[i] = stp2h->BridgeIdMAC[i];
	}

	AddMachineSTP(srcMAC);
}

void ScanMethodPassive::AddMachineSTP(BYTE* srcMacIn)
{
	MMachineInfo *mach;

	if(srcMacIn==NULL) return;

	addrX.Initialize();
	addrX.alive = true;
	addrX.respReceived = true;
	addrX.addrMAC.LoadFromBytePtr(srcMacIn);

	mach = machInfoList->GetMachineInfoByMacAddr(&addrX.addrMAC);
	if(mach!=NULL){
		mach->AddSTPPackNoDuplicates(&mstpX);
		return;
	}

	machX.Initialize();
	machX.address.LoadFromPointer(&addrX);
	machX.AddSTPPackNoDuplicates(&mstpX);

	machInfoList->Add(&machX);
}

//---------------------------------------------------------------------------

void ScanMethodPassive::ProcessGVRP(BYTE* dataIn, int sizeIn, BYTE* srcMAC)
{
	machInfoList->globalInfo.ethernetCounters.cntEthOther++;
	dataProcessed = true;

	GARPHeaderPG *garpH;
	GARPAttributePG *attr;
	bool doneMsg, doneAll;
	bool err;
	int pos, size;

	if(sizeIn<4) return;

	garpH = (GARPHeaderPG*)dataIn;

	gxrpX.Initialize();
	gxrpX.ProtocolType  = __gxrpGvrp;
	gxrpX.ProtocolID    = ntohs(garpH->ProtocolID);
	gxrpX.AttributeType = garpH->AttributeType;

	err     = false;
	doneMsg = false;
	doneAll = false;
	pos     = 3;
	while(!doneAll && !err){
		while(!doneMsg && !err){
			attr = (GARPAttributePG*)&dataIn[pos];

			size = (int)(attr->Length);
			pos += size;
			if(pos>=sizeIn) err = true;
			else{
				switch(size){
					case 0:	
						doneMsg = true;
						pos++;	// must be incremented here to go past the attribute list End mark
						break;
					case 1:
						err = true;	// should be two to four
						break;
					case 2 :
						err = !gxrpX.AddGvrpAttribute(attr->Length, attr->Event, 0, 0);
						break;
					case 3 :
						err = !gxrpX.AddGvrpAttribute(attr->Length, attr->Event, attr->Value.b.b0, 0);
						break;
					case 4 :
						err = !gxrpX.AddGvrpAttribute(attr->Length, attr->Event, attr->Value.b.b0, attr->Value.b.b1);
						break;
					default :
						err = true;	// should be two to four
						break;
				}
			}
		}

		if(!err)
			AddMachineGxRP(srcMAC);

		// pos should be at the next message or at the message End mark
		if(pos>=sizeIn) err = true;
		else{
			if(dataIn[pos]==0x00){
				// message End mark encountered, done, all messages readed, go home
				doneAll = true;
			}
			else{
				// prepare for the next message in frame
				gxrpX.AttributeType = dataIn[pos];
				gxrpX.Attributes.Clear();
				pos++; // to go to the attributes list
			}
		}
	}
}

void ScanMethodPassive::ProcessGMRP(BYTE* dataIn, int sizeIn, BYTE* srcMAC)
{
	machInfoList->globalInfo.ethernetCounters.cntEthOther++;
	dataProcessed = true;

/*
	gxrpX.ProtocolType  = __gxrpGmrp;
	gxrpX.ProtocolID    = ntohs(garpH->ProtocolID);
	gxrpX.AttributeType = garpH->AttributeType;
*/
}

void ScanMethodPassive::AddMachineGxRP(BYTE* srcMacIn)
{
	MMachineInfo *mach;

	if(srcMacIn==NULL) return;

	addrX.Initialize();
	addrX.alive = true;
	addrX.respReceived = true;
	addrX.addrMAC.LoadFromBytePtr(srcMacIn);

	mach = machInfoList->GetMachineInfoByMacAddr(&addrX.addrMAC);
	if(mach!=NULL){
		mach->AddGxRPPackNoDuplicates(&gxrpX);
		return;
	}

	machX.Initialize();
	machX.address.LoadFromPointer(&addrX);
	machX.AddGxRPPackNoDuplicates(&gxrpX);

	machInfoList->Add(&machX);
}

//---------------------------------------------------------------------------

void ScanMethodPassive::ProcessCDP(BYTE* dataIn, int sizeIn, BYTE* srcMAC)
{
	machInfoList->globalInfo.ethernetCounters.cntEthOther++;
	dataProcessed = true;

	CDPPacketHeaderPG *cdph;
	PacketTLVPG       *ptlv;
	MTLVRecord        rec;
	int               pos, reqSize, xLen;
	bool              err;

	if(sizeIn<6) return;	// CDPPacketHeaderPG + CDPPacketTLVPG
	cdph = (CDPPacketHeaderPG*)dataIn;

	mcdpX.Initialize();
	mcdpX.xVersion = cdph->Version;
	mcdpX.xTTL     = cdph->TTL;
	mcdpX.xChkSum  = cdph->ChkSum;

	pos = 4;
	err = false;
	while(pos<sizeIn && !err){
		ptlv = (PacketTLVPG*)&dataIn[pos];
		xLen = ntohs(ptlv->Length);
		if(xLen>=4){
			reqSize = pos + (unsigned int)xLen;
			if(reqSize<=sizeIn){
				rec.Initialize();
				rec.xType   = ntohs(ptlv->Type);
				rec.xLength = xLen;
				if(rec.xLength>4){
					// value present
					if(!rec.AddValueFromBytePtr(&dataIn[pos+4], rec.xLength - 4))
						err = true;
				}
			}
			else err = false;

			pos = reqSize;
		}
		else err = true;

		if(!err)
			if(!mcdpX.xValuesList.AddNoDuplicates(&rec))
				err = true;
	}

	AddMachineCDP(srcMAC);
}

void ScanMethodPassive::AddMachineCDP(BYTE* srcMacIn)
{
	MMachineInfo *mach;

	if(srcMacIn==NULL) return;

	addrX.Initialize();
	addrX.alive = true;
	addrX.respReceived = true;
	addrX.addrMAC.LoadFromBytePtr(srcMacIn);

	mach = machInfoList->GetMachineInfoByMacAddr(&addrX.addrMAC);
	if(mach!=NULL){
		mach->AddCDPPackNoDuplicates(&mcdpX);
		return;
	}

	machX.Initialize();
	machX.address.LoadFromPointer(&addrX);
	machX.AddCDPPackNoDuplicates(&mcdpX);

	machInfoList->Add(&machX);
}

//---------------------------------------------------------------------------

void ScanMethodPassive::ProcessDTP(BYTE* dataIn, int sizeIn, BYTE* srcMAC)
{
	PacketTLVPG *ptlv;
	MTLVRecord  rec;
	int         pos, reqSize, xLen;
	bool        err;

	machInfoList->globalInfo.ethernetCounters.cntEthOther++;
	dataProcessed = true;

	if(sizeIn<5) return;

	mdtpX.Initialize();
	mdtpX.xVersion = dataIn[0];

	pos = 1;
	err = false;
	while(pos<sizeIn && !err){
		ptlv = (PacketTLVPG*)&dataIn[pos];
		xLen = ntohs(ptlv->Length);
		if(xLen>=4){
			reqSize = pos + (unsigned int)xLen;
			if(reqSize<=sizeIn){
				rec.Initialize();
				rec.xType   = ntohs(ptlv->Type);
				rec.xLength = xLen;
				if(rec.xLength>4){
					// value present
					if(!rec.AddValueFromBytePtr(&dataIn[pos+4], rec.xLength - 4))
						err = true;
				}
			}
			else err = true;

			pos = reqSize;
		}
		else{
			if(xLen==0) pos = sizeIn;
			else        err = true;
		}

		if(!err && xLen>0)
			if(!mdtpX.xValuesList.AddNoDuplicates(&rec))
				err = true;
	}

	if(!err)
		AddMachineDTP(srcMAC);
}

void ScanMethodPassive::AddMachineDTP(BYTE* srcMacIn)
{
	MMachineInfo *mach;

	if(srcMacIn==NULL) return;

	addrX.Initialize();
	addrX.alive = true;
	addrX.respReceived = true;
	addrX.addrMAC.LoadFromBytePtr(srcMacIn);

	mach = machInfoList->GetMachineInfoByMacAddr(&addrX.addrMAC);
	if(mach!=NULL){
		mach->AddDTPPackNoDuplicates(&mdtpX);
		return;
	}

	machX.Initialize();
	machX.address.LoadFromPointer(&addrX);
	machX.AddDTPPackNoDuplicates(&mdtpX);

	machInfoList->Add(&machX);
}

//---------------------------------------------------------------------------

void ScanMethodPassive::ProcessOtherEthernetPacket(WORD lenTypeIn, BYTE* dataIn, int sizeIn, BYTE* srcMAC)
{
	machInfoList->globalInfo.ethernetCounters.cntEthOther++;
	dataProcessed = true;
}

//---------------------------------------------------------------------------
